package com.getword.web.controller;

import com.getword.domain.Video;
import com.getword.utils.*;
import com.getword.web.model.ConstantByProperties;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/api")
public class ApiUploadController {


    static final int BUFFER_LENGTH = 10240;
    static final String START_FIELD = "start";
    public static final String CONTENT_RANGE_HEADER = "content-range";

    @Autowired
    private ImageAsync imageAsync;

    @Autowired
    private VideoAsync videoAsync;

    @RequestMapping(value = "/uploadFile", method = RequestMethod.GET)
    public void uploadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
        long start = 0;
        boolean success = true;
        String message = "";
        JSONObject json = new JSONObject();
        final String token = request.getParameter(ApiTokenController.TOKEN_FIELD); // 文件名和大小的hashcode编码
        final String size = request.getParameter(ApiTokenController.FILE_SIZE_FIELD); // 文件大小
        final String fileName = request.getParameter(ApiTokenController.FILE_NAME_FIELD); // 文件名
        final PrintWriter writer = response.getWriter();
        try {
            doOptions(request, response);
            // 创建空文件，以及上级文件夹名
            File file = IoUtil.getTokenedFile(token);
            start = file.length();
            if (token.endsWith("_0") && "0".equals(size) && 0 == start)
                file.renameTo(IoUtil.getFile(fileName));
        } catch (FileNotFoundException e) {
            message = "Error: " + e.getMessage();
            success = false;
        } finally {
            try {
                if (success)
                    json.put(START_FIELD, start);
                json.put(ApiTokenController.SUCCESS, success);
                json.put(ApiTokenController.MESSAGE, message);
            } catch (JSONException e) {

            }
            writer.write(json.toString());
            IoUtil.close(writer);
        }
    }

    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    public void uploadFileListPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, Exception {
        doOptions(request, response);
        // 文件名和大小的hashcode编码
        final String token = request.getParameter(ApiTokenController.TOKEN_FIELD);
        // 文件名
        final String fileName = request.getParameter(ApiTokenController.FILE_NAME_FIELD);
        Range range = IoUtil.parseRange(request);
        OutputStream out = null;
        InputStream content = null;
        final PrintWriter writer = response.getWriter();

        JSONObject json = new JSONObject();
        long start = 0;
        boolean success = true;
        String message = "";
        File f = IoUtil.getTokenedFile(token);
        try {
            if (f.length() != range.getFrom()) {
                /** drop this uploaded data */
                throw new StreamException(StreamException.ERROR_FILE_RANGE_START);
            }

            out = new FileOutputStream(f, true);
            content = request.getInputStream();
            int read = 0;
            final byte[] bytes = new byte[BUFFER_LENGTH];
            while ((read = content.read(bytes)) != -1) {
                out.write(bytes, 0, read);
                try {
                    // 这里主要是控制读写速度，呈现给前端的是上传速度
                    Thread.sleep(ConstantByProperties.uploadSpeed);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            start = f.length();
        } catch (StreamException se) {
            success = StreamException.ERROR_FILE_RANGE_START == se.getCode();
            message = "Code: " + se.getCode();
            throw new StreamException(se.getCode());
        } catch (FileNotFoundException fne) {
            message = "Code: " + StreamException.ERROR_FILE_NOT_EXIST;
            success = false;
            throw new FileNotFoundException();
        } catch (IOException io) {
            message = "IO Error: " + io.getMessage();
            success = false;throw new IOException(io);
        } finally {
            IoUtil.close(out);
            IoUtil.close(content);

            /** rename the file */
            Map<String, String> map = new HashMap<String, String>();

            if (range.getSize() == start) {
                /** fix the `renameTo` bug */
                try {
                    String cgSubDir = ConstantByProperties.basePath;
                    String uuid = UUID.randomUUID().toString();

                    String fileSaveName = uuid + "." + fileName.split("\\.")[fileName.split("\\.").length - 1];

                    String url = cgSubDir + fileSaveName;

                    Path pathtrue = f.toPath().resolveSibling(url); // 真是路径
                    File parentFile = pathtrue.toFile().getParentFile();
                    if (!parentFile.exists()) {
                        parentFile.mkdirs();
                    }
                    Files.move(f.toPath(), pathtrue);

                    // 将保存的文件路径暂存在session中
                    Video video = new Video();
                    video.setVideoFilename(fileSaveName);
                    video.setVideoOriginalName(fileName);
                    video.setVideoExt(PathUtil.getFileExt(fileName));
                    request.getSession().setAttribute(ApiVideoController.VIDEO, video);


                    map.put("name", fileName);
                    map.put("uuid", uuid);
                    map.put("url", url);
                    // 获得上传后的文件对象,可以做一些后期的处理，比如生成图片缩略图，视频缩略图等等,最好用异步的方式去执行这些操作,开启异步配置自行百度
                    File newFile = pathtrue.toFile();

                    // 生成图片缩略图,生成缩略图存放的路径跟原图路径是相同的
//                    imageAsync.createThumbnail(newFile);
                    // 异步生成视频缩略图,第二个参数表示取(视频长度/xx)的那一帧作为缩略图
//                    videoAsync.randomGrabberFFmpegImage(pathtrue.toString(), 2);
                } catch (IOException e) {
                    e.printStackTrace();
                    success = false;
                    message = "Rename file error: " + e.getMessage();
                }
            }
            try {
                if (success) {
                    json.put(START_FIELD, start);
                    json.put("map", map);
                }
                json.put(ApiTokenController.SUCCESS, success);
                json.put(ApiTokenController.MESSAGE, message);
            } catch (JSONException e) {
                System.out.println(e.toString());
            }
            writer.write(json.toString());
            IoUtil.close(writer);
        }
    }

    private void doOptions(HttpServletRequest req, HttpServletResponse resp) throws UnsupportedEncodingException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json;charset=utf-8");
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Headers", "Content-Range,Content-Type");
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    }
}
